import datetime
from typing import List

from sqlalchemy import or_, and_
from sqlalchemy.orm import Session
from module_admin.entity.do.cms_order import CmsOrder
from module_admin.entity.do.cms_order_dispatch import CmsOrderDispatch
from module_admin.entity.do.cms_order_execute import CmsOrderExecute
from module_admin.entity.vo.cms_driver_vo import OrderListOrderChild, OrderListForQueryAfter
from utils.time_format_util import object_format_datetime, list_format_datetime


class CmsOrderDispatchDao:

    @classmethod
    def create_order_dispatch(cls, db: Session, entity: CmsOrderDispatch):
        db.add(entity)
        db.flush()
        db.commit()

    @classmethod
    def update_state_reason(cls, db: Session, order_id: str, driver_id: str, state: int, reason: str,
                            confirm_time: datetime.datetime):
        order_dispatch_first = (db.query(CmsOrderDispatch)
                                .filter(CmsOrderDispatch.order_id == order_id)
                                # .filter(CmsOrderDispatch.driver_id == driver_id)
                                .first())
        if order_dispatch_first is not None:
            if state is not None:
                order_dispatch_first.state = state
            if reason is not None:
                order_dispatch_first.reason = reason
            if confirm_time is not None:
                order_dispatch_first.confirm_time = confirm_time
            db.commit()

    @classmethod
    def get_one_by_order_id(cls, db: Session, order_id: str):
        first = db.query(CmsOrderDispatch).filter(CmsOrderDispatch.order_id == order_id).first()
        return object_format_datetime(first)

    @classmethod
    def get_one_by_order_id_and_driver_id(cls, db: Session, order_id: str, driver_id):
        first = (db.query(CmsOrderDispatch)
                 .filter(CmsOrderDispatch.order_id == order_id)
                 .filter(CmsOrderDispatch.driver_id == driver_id)
                 .first())
        return object_format_datetime(first)

    @classmethod
    def delete_one_by_order_id(cls, db: Session, order_id: str):
        db.query(CmsOrderDispatch) \
            .filter(CmsOrderDispatch.order_id == order_id) \
            .delete()
        db.commit()

    @classmethod
    def get_order_list_id_by_driver_id(cls, db: Session, driver_id: str):
        order_id_list = db.query(CmsOrderDispatch.order_id).filter(CmsOrderDispatch.driver_id == driver_id).all()
        order_id_list2 = {int(id[0]) for id in order_id_list}
        return order_id_list2

    @classmethod
    def list_by_driver_or_car(cls, db, driver_order_query: OrderListForQueryAfter):
        query_for_order = db.query(CmsOrderDispatch.order_id.label("order_id"),
                                   CmsOrderDispatch.confirm_time.label("confirm_time"),
                                   CmsOrderExecute.reality_begin_time.label("reality_begin_time"),
                                   CmsOrderExecute.reality_end_time.label("reality_end_time")) \
            .outerjoin(CmsOrderExecute, CmsOrderExecute.order_id == CmsOrderDispatch.order_id)
        filters = []
        if driver_order_query.driver_id and driver_order_query.driver_id.strip():
            filters.append(CmsOrderDispatch.driver_id == driver_order_query.driver_id)
        if driver_order_query.car_id and driver_order_query.car_id.strip():
            filters.append(CmsOrderDispatch.car_id == driver_order_query.car_id)
        if driver_order_query.query_begin:
            filters.append(
                CmsOrderDispatch.confirm_time >= driver_order_query.query_begin.strftime('%Y-%m-%d %H:%M:%S'))
        if driver_order_query.query_end:
            filters.append(
                CmsOrderDispatch.confirm_time <= driver_order_query.query_end.strftime('%Y-%m-%d %H:%M:%S'))
        if filters:
            query_for_order = query_for_order.filter(*filters)
        driver_order_list: List[OrderListOrderChild] = query_for_order.all()
        post_list_bill_page = []
        for e in driver_order_list:
            listo = OrderListOrderChild()
            listo.order_id = e.order_id
            listo.confirm_time = e.confirm_time
            listo.reality_begin_time = e.reality_begin_time
            listo.reality_end_time = e.reality_end_time
            post_list_bill_page.append(listo)
        return post_list_bill_page
